package IA;

import java.util.ArrayList;
import java.util.List;

public class SystemClock implements Runnable {

    public final int DEFAULT_TIMESCALE = 100; //ms per tick (real time 1 tick = 1 min = 60000 ms)
    private int MSPT; //millseconds per tick, the time scale
    private boolean Paused = false;
    private boolean Running = false;
    private ArrayList<ClockObserverInterface> Observers = new ArrayList<ClockObserverInterface>();
    private static SystemClock instance = null;
    List<ClockObserverInterface> addList = new ArrayList<ClockObserverInterface>();
    List<ClockObserverInterface> removeList = new ArrayList<ClockObserverInterface>();
    private boolean notifying = false;

    private SystemClock() {
        MSPT = DEFAULT_TIMESCALE;
    }

    public static SystemClock getInstance() {
        if (instance == null) {
            instance = new SystemClock();
            return instance;
        } else {
            return instance;
        }
    }

    @Override
    public void run() {
        TimeLoop();
    }

    private void TimeLoop() {
        long start = System.currentTimeMillis();
        while (true) {
            try {
                Thread.sleep(0);
            } catch (InterruptedException e) {
                System.out.println(e.getMessage());
            }
            while (Running) {
                if (System.currentTimeMillis() >= (start + MSPT)) {
                    if (!Paused) {
                        NotifyAll();
                        start = System.currentTimeMillis();
                    }
                }
            }
        }
    }

    public void setTimeScale(int MSPerTick) {
        MSPT = MSPerTick;
    }

    public int getTimeScale() {
        return MSPT;
    }

    private void NotifyAll() {
        for (ClockObserverInterface ob : Observers) {
            notifying = true;
            ob.clockTick();
        }
        notifying = false;
        for (int i = 0; i < addList.size(); i++) {
            Observers.add(addList.remove(i));
        }
        for (int i = 0; i < removeList.size(); i++) {
            Observers.remove(removeList.remove(i));
        }
    }

    public void AddObserver(ClockObserverInterface ob) {
        if (notifying) {
            addList.add(ob);
        } else {
            Observers.add(ob);
        }
    }

    public void RemoveObserver(ClockObserverInterface ob) {
        if (notifying) {
            removeList.add(ob);
        } else {
            Observers.remove(ob);
        }
    }

    public boolean isRunning() {
        return Running;
    }

    public void setRunning(boolean Running) {
        this.Running = Running;
    }
}
